#include "pch.h"
#include "Client.h"
#include "grpc++/grpc++.h"
#include "../Tinyxml2/tinyxml2.h"
#include "../Config/ImportDataConfig.h"
#include "../Config/SyncDataCmd.h"

Client::Client(const std::string &config_file)
    : config_file_(config_file)
{
    loadConfig(config_file_);

    stub_ = enclave::EnclaveServer::NewStub(grpc::CreateChannel(service_address_, grpc::InsecureChannelCredentials()));
}

Client::~Client()
{
}

void Client::importData(const std::string & import_data)
{
    ImportDataConfig import_data_config(import_data);

    enclave::ImportDataRequest request;
    request.set_host(import_data_config.database_.host_);
    request.set_port(import_data_config.database_.port_);
    request.set_database(import_data_config.database_.database_);
    request.set_user(import_data_config.database_.user_);
    request.set_password(import_data_config.database_.password_);

    for (auto iter = import_data_config.tables_.begin(); iter != import_data_config.tables_.end(); ++iter)
    {
        auto table = request.add_tables();
        table->set_name(iter->name_);
        table->set_orderbyfield(iter->order_by_field_);

        for (auto field_iter = iter->fields_.begin(); field_iter != iter->fields_.end(); ++field_iter)
        {
            auto field = table->add_fields();
            field->set_name(field_iter->name_);
        }

		for (auto field_iter = iter->ope_fields_.begin(); field_iter != iter->ope_fields_.end(); ++field_iter)
		{
			auto field = table->add_opefields();
			field->set_name(field_iter->name_);
		}
    }

    grpc::ClientContext context;
    auto client_reader = stub_->ImportData(&context, request);

    enclave::ImportDataResponse response;
    while (client_reader->Read(&response))
    {
        for (int i = 0; i < response.tables_size(); ++i)
        {
			LOG(INFO) << response.tables(i).name() << ", count = " << response.tables(i).datacount() << ", imported count = " << response.tables(i).importeddatacount();
        }
    }

	client_reader->Finish();

	LOG(INFO) << "import data Finished";
}

void Client::search(const std::string & file_name)
{
	tinyxml2::XMLDocument doc;
	auto ret = doc.LoadFile(file_name.c_str());
	if (ret != tinyxml2::XML_SUCCESS)
	{
		std::cout << "load config file faild: " << file_name << ", error code is " << ret << std::endl;
		return;
	}

	if (auto search_element = doc.FirstChildElement("search"))
	{
		enclave::searchRequest request;

		if (auto sql_element = search_element->FirstChildElement("sql"))
		{
			const char* sql = sql_element->GetText();
			if (sql != nullptr)
			{
				request.set_sql(sql);
			}
		}

		if (auto args_element = search_element->FirstChildElement("args"))
		{
			auto arg_element = args_element->FirstChildElement("arg");
			while (arg_element != nullptr)
			{
				auto value = request.add_values();

				auto type = arg_element->Attribute("type");
				if (type != nullptr)
				{
					if (strcmp(type, "int") == 0)
					{
						value->set_type(enclave::searchRequest::valueType::searchRequest_valueType_intType);
					}
					else
					{
						value->set_type(enclave::searchRequest::valueType::searchRequest_valueType_stringType);
					}
				}

				if (auto value_text = arg_element->GetText())
				{
					value->set_value(value_text);
				}

				arg_element = arg_element->NextSiblingElement("arg");
			}
		}

		grpc::ClientContext context;

		auto client_reader = stub_->Search(&context, request);

		enclave::Rows response;
		while (client_reader->Read(&response))
		{
			LOG(INFO) << response.tablename() << "count = " << response.total() << " pos = " << response.pos();

			for (int i = 0; i < response.rows_size(); i++)
			{
				LOG(INFO) << response.rows(i).values();
			}
		}

		client_reader->Finish();

		std::cout << "search data Finished" << std::endl;
	}
}

void Client::syncCmd(const std::string &file_name)
{
    SyncDataCmd sync_data_cmd;
    if (sync_data_cmd.loadFile(file_name) == false)
    {
        return;
    }

	enclave::SyncCmdRequest request;

	request.set_host(sync_data_cmd.vault.host_);
	request.set_port(sync_data_cmd.vault.port_);
	request.set_vaultid(sync_data_cmd.vault.id_);

	LOG(INFO) << "Send sync cmd , vault id = " << sync_data_cmd.vault.id_ << ", host = " << sync_data_cmd.vault.host_ << ", port = " << sync_data_cmd.vault.port_;

	enclave::SyncCmdResponse response;

	grpc::ClientContext context;

	stub_->SyncCmd(&context, request, &response);

	LOG(INFO) << "response valut id: " << response.vaultid();
}

void Client::loadConfig(const std::string & config_file)
{
    tinyxml2::XMLDocument doc;
    auto ret = doc.LoadFile(config_file.c_str());
    if (ret != tinyxml2::XML_SUCCESS)
    {
        std::cout << "load config file faild: " << config_file << ", error code is " << ret << std::endl;
        return;
    }

    if (auto client_element = doc.FirstChildElement("client"))
    {
        if (auto service_element = client_element->FirstChildElement("service"))
        {
            service_address_ = service_element->GetText();
        }
    }
}
